﻿namespace Okazuki.MVVM.PrismSupport.ViewModels
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Windows.Input;
    using Microsoft.Practices.Prism.Commands;
    using Microsoft.Practices.Prism.ViewModel;
    using Okazuki.MVVM.PrismSupport.Utils;
    using Okazuki.MVVM.PrismSupport.ViewModels.Utils;

    /// <summary>
    /// ViewModelの基本クラス。
    /// AutoInit属性のついたプロパティのインスタンスの自動初期化機能と、DelegateCommandのプロパティと
    /// CommandManager.RequerySuggestedの自動接続機能を提供します。
    /// </summary>
    public abstract class ViewModelBase : NotificationObject
    {
        /// <summary>
        /// 自動初期化をするDelegateCommandのプロパティ
        /// </summary>
        [AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
        internal protected class AutoInitCommandAttribute : Attribute
        {
        }

        /// <summary>
        /// DelegateCommandに渡すメソッド
        /// </summary>
        [AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
        internal protected class CommandMethodAttribute : Attribute
        {
            /// <summary>
            /// コマンド名(指定しない場合はメソッド名から推測する
            /// </summary>
            public string Name { get; set; }
        }

        /// <summary>
        /// ViewModelの初期化を行います
        /// </summary>
        protected ViewModelBase()
        {
            ViewModelInitializer.InitializeViewModel(this);
            this.InitializeAutoInitProperties();
        }

        /// <summary>
        /// AutoInitAttributeのついているIInteractionRequestの派生型のプロパティの値を初期化します。
        /// </summary>
        private void InitializeAutoInitProperties()
        {
            ObjectUtils.Init(this);
        }

        /// <summary>
        /// CommandManager.RequerySuggestedへのイベントハンドラの参照を保持します。
        /// </summary>
        private IList<EventHandler> requerySuggestedEventHandlers = new List<EventHandler>();

        internal IList<EventHandler> RequerySuggestedEventHandlers
        {
            get
            {
                return requerySuggestedEventHandlers;
            }
        }

        /// <summary>
        /// NotifyPropertyWeaver用プロパティ変更通知メソッド
        /// </summary>
        /// <param name="propertyName">プロパティ名</param>
        protected void OnPropertyChanged(string propertyName)
        {
            this.RaisePropertyChanged(propertyName);
        }

#if SILVERLIGHT
        /// <summary>
        /// プロパティの変更通知を行います。
        /// </summary>
        /// <param name="propertyName"></param>
        protected override void RaisePropertyChanged(string propertyName)
        {
            base.RaisePropertyChanged(propertyName);
            CommandManager.InvalidateRequerySuggested();
        }
#endif
    }
}
